const ROWS = 4;
const NUMBERS = [2, 4];
const MIN_LENGTH = 50;
const MOVE_DURATION = 0.1;

cc.Class({
    extends: cc.Component,

    properties: {
        scoreLabel: cc.Label,
        score: 0,
        blockPrefab: cc.Prefab,
        gap: 20,
        bg: cc.Node,
        mainBgView: cc.Node,
        gameOverView: cc.Node,
        victoryView: cc.Node
    },

    start() {
        this.resetGame();
        this.addEventHandler();
    },

    resetGame(){
        this.updateScore(0);
        this.drawBGblock();
        this.init();
    },

    /**
     * 第一次布局
     */
    drawBGblock() {
        this.blocksize = (cc.winSize.width - this.gap * (ROWS + 1)) / ROWS;
        let x = this.gap + this.blocksize / 2;
        let y = this.blocksize;
        this.positions = [];

        for (var i = 0; i < ROWS; i++) {
            this.positions.push([0, 0, 0, 0]);
            for (var j = 0; j < ROWS; j++) {
                let block = cc.instantiate(this.blockPrefab);
                block.width = this.blocksize;
                block.height = this.blocksize;
                this.bg.addChild(block);
                block.setPosition(cc.v2(x, y));
                this.positions[i][j] = cc.v2(x, y);
                x += this.gap + this.blocksize;
                block.getComponent('block').setNumber(0);
            }
            y += this.gap + this.blocksize;
            x = this.gap + this.blocksize / 2;
        }
    },

    /**
     * 初始化 方法
     */
    init() {
        this.updateScore(0);

        if (this.blocks) {
            for (var i = 0; i < ROWS; i++) {
                for (var j = 0; j < ROWS; j++) {
                    if (this.blocks[i][j] != null) {
                        this.blocks[i][j].destroy();
                    }
                }
            }
        }

        this.data = [];
        this.blocks = [];
        for (let i = 0; i < ROWS; i++) {
            this.blocks.push([null, null, null, null])
            this.data.push([0, 0, 0, 0])
        }

        this.addBlock();
        this.addBlock();
        this.addBlock();
    },
    /**
     * 更新分数
     */
    updateScore(number) {
        this.score = number;
        this.scoreLabel.string = '分数：' + number;
    },
    /**
     * 获取 空值
     */
    getEmptLocations() {
        let locations = [];
        for (var i = 0; i < this.blocks.length; i++) {
            for (var j = 0; j < this.blocks[i].length; j++) {
                if (this.blocks[i][j] == null) {
                    locations.push({
                        x: i,
                        y: j
                    });
                }
            }
        }
        return locations;
    },

    /**
     * 生成 随机数
     */
    addBlock() {
        let locations = this.getEmptLocations();
        if (locations.length == 0) {
            return false;
        }
        let index = locations[Math.floor(Math.random() * locations.length)];
        let x = index.x;
        let y = index.y;
        let position = this.positions[x][y];

        let block = cc.instantiate(this.blockPrefab);
        block.width = this.blocksize;
        block.height = this.blocksize;
        this.bg.addChild(block);
        block.setPosition(position);
        let numberValue = NUMBERS[Math.floor(Math.random() * NUMBERS.length)];
        block.getComponent('block').setNumber(numberValue);
        this.blocks[x][y] = block;
        this.data[x][y] = numberValue;
        return true;
    },

    /**
     *  手势 事件监听
     */
    addEventHandler() {
        this.bg.on('touchstart', (envent) => {
            this.startPoint = envent.getLocation();
        });

        this.bg.on('touchend', (envent) => {
            this.touchEnd(envent);
        });

        this.bg.on('touchcancel', (envent) => {
            this.touchEnd(envent);
        });
    },

    touchEnd(event) {
        this.endPoint = event.getLocation();
        let vec = this.endPoint.sub(this.startPoint);
        if (vec.mag() > MIN_LENGTH) {
            if (Math.abs(vec.x) > Math.abs(vec.y)) {
                // 水平方向
                if (vec.x > 0) {
                    this.moveRight();
                } else {
                    this.moveLeft();
                }
            } else {
                // 垂直方向
                if (vec.y > 0) {
                    this.moveUP();
                } else {
                    this.moveDown();
                }
            }
        }
    },

    /**
     * 移动结束
     */
    afterMove(hasMoved) {
        if (hasMoved) {
            this.updateScore(this.score + 1);
            this.addBlock();
        }
        if (this.checkFail()) {
            this.gameOver();
        }
    },

    /**
     * 检验是否失败
     */
    checkFail() {
        for (var i = 0; i < ROWS; i++) {
            for (var j = 0; j < ROWS; j++) {
                let n = this.data[i][j];
                if (n == 0) {
                    return false;
                }
                if (j > 0 && this.data[i][j - 1] == n) {
                    return false;
                }
                if (i > 0 && this.data[i - 1][j] == n) {
                    return false;
                }
                if (j < 3 && this.data[i][j + 1] == n) {
                    return false;
                }
                if (i < 3 && this.data[i + 1][j] == n) {
                    return false;
                }
            }
        }
        return true;
    },
   
    /**
     *  移动 方块
     *
     * @param {cc.Node} block
     * @param {cc.p} position
     * @param {func} callback
     */
    doMove(block, position, callback) {
        let action = cc.moveTo(MOVE_DURATION, position);
        let finsh = cc.callFunc(() => {
            callback && callback();
        });
        block.runAction(cc.sequence(action, finsh));
    },

    moveRight() {
        cc.log('moveRight');
        // 是否可以创建 新方块
        let hasMoved = false;
        // 游戏结束  恭喜成功
        let hasVictory = false;
        let move = (x, y, callback) => {
            if (y == ROWS - 1 || this.data[x][y] == 0) {
                callback && callback();
                return;
            } else if (this.data[x][y + 1] == 0) {
                // 移动 拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x][y + 1];
                // 替换将要替换的方块
                this.blocks[x][y + 1] = block;
                this.data[x][y + 1] = this.data[x][y];
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;
                this.doMove(block, position, () => {
                    move(x, y + 1, callback);
                })
                hasMoved = true;
            } else if (this.data[x][y + 1] == this.data[x][y]) {
                // 合并  拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x][y + 1];
                // 合并 方块
                this.data[x][y + 1] *= 2;
                if (this.data[x][y + 1] == 2048) {
                    hasVictory = true;
                }
                // 重新 给这个方块 赋值
                this.blocks[x][y + 1].getComponent('block').setNumber(this.data[x][y + 1]);
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;

                this.doMove(block, position, () => {
                    block.destroy();
                    callback && callback();
                })
                hasMoved = true;
            } else {
                callback && callback();
                return;
            }
        };

        // 拿到 所有有值 的方块 且要按顺序
        let tomove = [];
        for (var i = 0; i < ROWS; i++) {
            for (var j = ROWS - 1; j >= 0; j--) {
                if (this.data[i][j] != 0) {
                    tomove.push({
                        x: i,
                        y: j
                    });
                }
            }
        }

        // 让所有 有值得方块都递归一遍
        let counter = 0;
        for (var i = 0; i < tomove.length; i++) {
            move(tomove[i].x, tomove[i].y, () => {
                counter++;
                if (hasVictory) {
                    console.log('你赢了')
                    this.gameVictoryClick();
                    return;
                }
                if (counter == tomove.length) {
                    this.afterMove(hasMoved);
                }
            })
        }
    },

    moveLeft() {
        cc.log('moveLeft');
        // 是否可以创建 新方块
        let hasMoved = false;
        // 游戏结束  恭喜成功
        let hasVictory = false;
        let move = (x, y, callback) => {
            if (y == 0 || this.data[x][y] == 0) {
                callback && callback();
                return;
            } else if (this.data[x][y - 1] == 0) {
                // 移动 拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x][y - 1];
                // 替换将要替换的方块
                this.blocks[x][y - 1] = block;
                this.data[x][y - 1] = this.data[x][y];
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;
                this.doMove(block, position, () => {
                    move(x, y - 1, callback);
                })
                hasMoved = true;
            } else if (this.data[x][y - 1] == this.data[x][y]) {
                // 合并  拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x][y - 1];
                // 合并 方块
                this.data[x][y - 1] *= 2;
                if (this.data[x][y - 1] == 2048) {
                    hasVictory = true;
                }
                // 重新 给这个方块 赋值
                this.blocks[x][y - 1].getComponent('block').setNumber(this.data[x][y - 1]);
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;

                this.doMove(block, position, () => {
                    block.destroy();
                    callback && callback();
                })
                hasMoved = true;
            } else {
                callback && callback();
                return;
            }
        };

        // 拿到 所有有值 的方块
        let tomove = [];
        for (var i = 0; i < ROWS; i++) {
            for (var j = 0; j < ROWS; j++) {
                if (this.data[i][j] != 0) {
                    tomove.push({
                        x: i,
                        y: j
                    });
                }
            }
        }

        // 让所有 有值得方块都递归一遍
        let counter = 0;
        for (var i = 0; i < tomove.length; i++) {
            move(tomove[i].x, tomove[i].y, () => {
                counter++;
                if (hasVictory) {
                    console.log('你赢了')
                    this.gameVictoryClick();
                    return;
                }
                if (counter == tomove.length) {
                    this.afterMove(hasMoved);
                }
            })
        }
    },

    moveUP() {
        cc.log('moveUP');
        // 是否可以创建 新方块
        let hasMoved = false;
        // 游戏结束  恭喜成功
        let hasVictory = false;
        let move = (x, y, callback) => {
            if (x == ROWS - 1 || this.data[x][y] == 0) {
                callback && callback();
                return;
            } else if (this.data[x + 1][y] == 0) {
                // 移动 拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x + 1][y];
                // 替换将要替换的方块
                this.blocks[x + 1][y] = block;
                this.data[x + 1][y] = this.data[x][y];
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;
                this.doMove(block, position, () => {
                    move(x + 1, y, callback);
                })
                hasMoved = true;
            } else if (this.data[x + 1][y] == this.data[x][y]) {
                // 合并  拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x + 1][y];
                // 合并 方块
                this.data[x + 1][y] *= 2;
                if (this.data[x + 1][y] == 2048) {
                    hasVictory = true;
                }
                // 重新 给这个方块 赋值
                this.blocks[x + 1][y].getComponent('block').setNumber(this.data[x + 1][y]);
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;

                this.doMove(block, position, () => {
                    block.destroy();
                    callback && callback();
                })
                hasMoved = true;
            } else {
                callback && callback();
                return;
            }
        };

        // 拿到 所有有值 的方块
        let tomove = [];
        for (var i = ROWS - 1; i >= 0; i--) {
            for (var j = 0; j < ROWS; j++) {
                if (this.data[i][j] != 0) {
                    tomove.push({
                        x: i,
                        y: j
                    });
                }
            }
        }

        // 让所有 有值得方块都递归一遍
        let counter = 0;
        for (var i = 0; i < tomove.length; i++) {
            move(tomove[i].x, tomove[i].y, () => {
                counter++;
                if (hasVictory) {
                    console.log('你赢了')
                    this.gameVictoryClick();
                    return;
                }
                if (counter == tomove.length) {
                    this.afterMove(hasMoved);
                }
            })
        }

    },
    moveDown() {
        cc.log('moveDown');
        // 是否可以创建 新方块
        let hasMoved = false;
        // 游戏结束  恭喜成功
        let hasVictory = false;
        let move = (x, y, callback) => {
            if (x == 0 || this.data[x][y] == 0) {
                callback && callback();
                return;
            } else if (this.data[x - 1][y] == 0) {
                // 移动 拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x - 1][y];
                // 替换将要替换的方块
                this.blocks[x - 1][y] = block;
                this.data[x - 1][y] = this.data[x][y];
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;
                this.doMove(block, position, () => {
                    move(x - 1, y, callback);
                })
                hasMoved = true;
            } else if (this.data[x - 1][y] == this.data[x][y]) {
                // 合并  拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x - 1][y];
                // 合并 方块
                this.data[x - 1][y] *= 2;
                if (this.data[x - 1][y] == 2048) {
                    hasVictory = true;
                }
                // 重新 给这个方块 赋值
                this.blocks[x - 1][y].getComponent('block').setNumber(this.data[x - 1][y]);
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;

                this.doMove(block, position, () => {
                    block.destroy();
                    callback && callback();
                })
                hasMoved = true;
            } else {
                callback && callback();
                return;
            }
        };

        // 拿到 所有有值 的方块
        let tomove = [];
        for (var i = 0; i < ROWS; i++) {
            for (var j = 0; j < ROWS; j++) {
                if (this.data[i][j] != 0) {
                    tomove.push({
                        x: i,
                        y: j
                    });
                }
            }
        }

        // 让所有 有值得方块都递归一遍
        let counter = 0;
        for (var i = 0; i < tomove.length; i++) {
            move(tomove[i].x, tomove[i].y, () => {
                counter++;
                if (hasVictory) {
                    console.log('你赢了')
                    this.gameVictoryClick();
                    return;
                }
                if (counter == tomove.length) {
                    this.afterMove(hasMoved);
                }
            })
        }
    },

    ageinGanmeClick(){
        cc.log('再来一次')
        this.gameOverView.active = false;
        this.victoryView.active = false;
        this.resetGame();
    },

    gameOver() {
        cc.log('笨蛋 失败了 脑残！！！！！！！！！！！')
        this.gameOverView.active = true;
    },

    gameVictoryClick(){
        cc.log('游戏 通关')
        this.victoryView.active = true;
    },

    moveSquare() {
        // 是否可以创建 新方块
        let hasMoved = false;
        // 游戏结束  恭喜成功
        let hasVictory = false;
        // 拿到 所有有值 的方块
        let tomove = [];
        for (var i = 0; i < ROWS; i++) {
            for (var j = 0; j < ROWS; j++) {
                if (this.data[i][j] != 0) {
                    tomove.push({
                        x: i,
                        y: j
                    });
                }
            }
        }

        // 让所有 有值得方块都递归一遍
        let counter = 0;
        for (var i = 0; i < tomove.length; i++) {
            move(tomove[i].x, tomove[i].y, () => {
                counter++;
                if (hasVictory) {
                    console.log('你赢了')
                    this.gameVictoryClick();
                    return;
                }
                if (counter == tomove.length) {
                    this.afterMove(hasMoved);
                }
            })
        }

        let move = (x, y, callback) => {
            if (x == 0 || this.data[x][y] == 0) {
                callback && callback();
                return;
            } else if (this.data[x - 1][y] == 0) {
                // 移动 拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x - 1][y];
                // 替换将要替换的方块
                this.blocks[x - 1][y] = block;
                this.data[x - 1][y] = this.data[x][y];
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;
                this.doMove(block, position, () => {
                    move(x - 1, y, callback);
                })
                hasMoved = true;
            } else if (this.data[x - 1][y] == this.data[x][y]) {
                // 合并  拿到当前 放款的值 和位置
                let block = this.blocks[x][y];
                let position = this.positions[x - 1][y];
                // 合并 方块
                this.data[x - 1][y] *= 2;
                if (this.data[x - 1][y] == 2048) {
                    hasVictory = true;
                }
                // 重新 给这个方块 赋值
                this.blocks[x - 1][y].getComponent('block').setNumber(this.data[x - 1][y]);
                // 重置 当前的方块
                this.data[x][y] = 0;
                this.blocks[x][y] = null;

                this.doMove(block, position, () => {
                    block.destroy();
                    callback && callback();
                })
                hasMoved = true;
            } else {
                callback && callback();
                return;
            }
        };
    }


    // update (dt) {},
});